using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.Reflection;
using INI;

using FullMotion.LiveForSpeed.InSim;
using FullMotion.LiveForSpeed.InSim.Enums;
using FullMotion.LiveForSpeed.InSim.Events;

namespace OvalRaceControl
{
    class Program
    {
        private string ip;
        private int port;
        private string adminPass;
        private Boolean useTCP = true;
        private char prefix;
        private byte numPlayers;
        private char trackCond = 'g';
        private char pitLane = 'o';
        private int penalty = 0;
        private int rcmClear;
        private Boolean hideButton;
        private string pitClosedText;
        private string pitClosedButton;
        private string pitOpenText;
        private string pitOpenButton;
        private string trackGreenButton;
        private string trackYellowButton;
        private string trackRedButton;
        private string trackRestartButton;
        private byte ButtonW;
        private byte ButtonH;
        private byte ButtonT;
        private byte ButtonL;
        private string greenTrackText;
        private string yellowTrackText;
        private string redTrackText;
        private string restartTrackText;
        private string adminCommand;
        private string penaltyMessage;

        private int helplines;
        private string helpfile;

        private InSimHandler handler = new InSimHandler();
        private Hashtable racerDatabase = new Hashtable();
        private string fgTitle;
        private string fgVersion;
        private string fgCompany;

        private LfsButton[] help;
        private LfsButton OK = new LfsButton(50);
        private LfsButton PitLane = new LfsButton(52);
        private LfsButton TrackCond = new LfsButton(51);
        private LfsButton openPit = new LfsButton(53);
        private LfsButton closedPit = new LfsButton(54);
        private LfsButton greenTrack = new LfsButton(55);
        private LfsButton yellowTrack = new LfsButton(56);
        private LfsButton redTrack = new LfsButton(57);
        private LfsButton noPenalty = new LfsButton(58);
        private LfsButton dtPenalty = new LfsButton(59);
        private LfsButton sgPenalty = new LfsButton(60);
        private LfsButton thirtyPenalty = new LfsButton(61);
        private LfsButton fortyfivePenalty = new LfsButton(62);
        private LfsButton closeMenu = new LfsButton(63);
        private LfsButton header = new LfsButton(64);
        private LfsButton trackHeader = new LfsButton(65);
        private LfsButton pitHeader = new LfsButton(66);
        private LfsButton penaltyHeader = new LfsButton(67);
        private LfsButton restartTrack = new LfsButton(68);

        static void Main(string[] args)
        {
            try
            {
                Program p = new Program();
                p.Config();
                p.Setup();
                p.Start();
                p.Threading();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                Console.ReadLine();
                Environment.Exit(0);
            }
        }

        public void Config()
        {
            try
            {
                IniFile ini = new IniFile(".\\config.ini");
                ip = ini.IniReadValue("server", "ip");
                port = Convert.ToInt32(ini.IniReadValue("server", "port"));
                adminPass = ini.IniReadValue("server", "admin pass");
                //useTCP = Convert.ToBoolean(ini.IniReadValue("server", "use tcp"));
                prefix = Convert.ToChar(ini.IniReadValue("server", "insim prefix"));

                helplines = Convert.ToInt16(ini.IniReadValue("help", "number of lines"));
                help = new LfsButton[helplines];
                helpfile = ini.IniReadValue("help", "file location");

                hideButton = Convert.ToBoolean(ini.IniReadValue("options", "hide on green"));
                rcmClear = Convert.ToInt32(ini.IniReadValue("options", "rcm clear"));
                adminCommand = ini.IniReadValue("options", "admin command");
                ButtonW = Convert.ToByte(ini.IniReadValue("buttons", "ButtonW"));
                ButtonH = Convert.ToByte(ini.IniReadValue("buttons", "ButtonH"));
                ButtonT = Convert.ToByte(ini.IniReadValue("buttons", "ButtonT"));
                ButtonL = Convert.ToByte(ini.IniReadValue("buttons", "ButtonL"));
                pitClosedText = ini.IniReadValue("language translations", "pits closed message");
                pitClosedButton = ini.IniReadValue("language translations", "pits closed button");
                pitOpenText = ini.IniReadValue("language translations", "pits open message");
                pitOpenButton = ini.IniReadValue("language translations", "pits open button");
                greenTrackText = ini.IniReadValue("language translations", "track green message");
                yellowTrackText = ini.IniReadValue("language translations", "track yellow message");
                redTrackText = ini.IniReadValue("language translations", "track red message");
                trackGreenButton = ini.IniReadValue("language translations", "track green button");
                trackYellowButton = ini.IniReadValue("language translations", "track yellow button");
                trackRedButton = ini.IniReadValue("language translations", "track red button");
                trackRestartButton = ini.IniReadValue("language translations", "track restart button");
                restartTrackText = ini.IniReadValue("language translations", "track restart message");
                penaltyMessage = ini.IniReadValue("language translations", "penalty text");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Config.ini file missing, or option not formatted correctly.");
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                Console.ReadLine();
                Environment.Exit(0);
            }
        }

        public void Setup()
        {
            byte buttoncount = 0;

            try
            {
                StreamReader re = File.OpenText(helpfile);

                for (int i = 0; i < helplines; i++)
                {
                    help[i] = new LfsButton(buttoncount);
                    help[i].Width = 160;
                    help[i].Left = 20;
                    help[i].Top = (byte)(10 + (i * 5));
                    help[i].Height = 5;
                    help[i].TextAlignment = ButtonTextAlignment.Left;
                    help[i].Color = ButtonColor.Dark;
                    help[i].TextColor = ButtonTextColor.SelectedText;

                    string input = "";
                    if ((input = re.ReadLine()) != null)
                    {
                        if (input.StartsWith("[H]"))
                        {
                            help[i].TextColor = ButtonTextColor.TitleColor;
                            input = input.Substring(3);
                        }
                        help[i].Text = input;
                    }
                    buttoncount++;
                }
                re.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.Source);
                Console.ReadLine();
                Environment.Exit(0);
            }

            OK.Text = "OK";
            OK.Left = 20;
            OK.TextAlignment = ButtonTextAlignment.Center;
            OK.Height = 10;
            OK.Color = ButtonColor.Light;
            OK.TextColor = ButtonTextColor.Ok;
            OK.Width = 20;
            OK.Top = (byte)(10 + (help.Length * 5));
            OK.Clickable = true;

            PitLane.Text = pitOpenButton;
            PitLane.Left = ButtonL;
            PitLane.Top = ButtonT;
            PitLane.Width = ButtonW;
            PitLane.Height = ButtonH;
            PitLane.TextAlignment = ButtonTextAlignment.Center;
            PitLane.Color = ButtonColor.Dark;
            PitLane.TextColor = ButtonTextColor.Ok;

            TrackCond.Text = trackGreenButton;
            TrackCond.Left = Convert.ToByte(ButtonL + ButtonW);
            TrackCond.Top = ButtonT;
            TrackCond.Width = ButtonW;
            TrackCond.Height = ButtonH;
            TrackCond.TextAlignment = ButtonTextAlignment.Center;
            TrackCond.Color = ButtonColor.Dark;
            TrackCond.TextColor = ButtonTextColor.Cancel;

            openPit.Text = "Open Pitlane";
            openPit.Left = 80;
            openPit.Top = 30;
            openPit.Width = 20;
            openPit.Height = 10;
            openPit.TextAlignment = ButtonTextAlignment.Center;
            openPit.Color = ButtonColor.Dark;
            openPit.TextColor = ButtonTextColor.Ok;
            openPit.Clickable = true;

            closedPit.Text = "Close Pitlane";
            closedPit.Left = 100;
            closedPit.Top = 30;
            closedPit.Width = 20;
            closedPit.Height = 10;
            closedPit.TextAlignment = ButtonTextAlignment.Center;
            closedPit.Color = ButtonColor.Dark;
            closedPit.TextColor = ButtonTextColor.Cancel;
            closedPit.Clickable = true;

            greenTrack.Text = "GREEN";
            greenTrack.Left = 80;
            greenTrack.Top = 20;
            greenTrack.Width = 20;
            greenTrack.Height = 10;
            greenTrack.TextAlignment = ButtonTextAlignment.Center;
            greenTrack.Color = ButtonColor.Dark;
            greenTrack.TextColor = ButtonTextColor.Ok;
            greenTrack.Clickable = true;

            yellowTrack.Text = "YELLOW";
            yellowTrack.Left = 100;
            yellowTrack.Top = 20;
            yellowTrack.Width = 20;
            yellowTrack.Height = 10;
            yellowTrack.TextAlignment = ButtonTextAlignment.Center;
            yellowTrack.Color = ButtonColor.Dark;
            yellowTrack.TextColor = ButtonTextColor.TitleColor;
            yellowTrack.Clickable = true;

            redTrack.Text = "RED";
            redTrack.Left = 140;
            redTrack.Top = 20;
            redTrack.Width = 20;
            redTrack.Height = 10;
            redTrack.TextAlignment = ButtonTextAlignment.Center;
            redTrack.Color = ButtonColor.Dark;
            redTrack.TextColor = ButtonTextColor.Cancel;
            redTrack.Clickable = true;

            restartTrack.Text = "SC Restart";
            restartTrack.Left = 120;
            restartTrack.Top = 20;
            restartTrack.Width = 20;
            restartTrack.Height = 10;
            restartTrack.TextAlignment = ButtonTextAlignment.Center;
            restartTrack.Color = ButtonColor.Dark;
            restartTrack.TextColor = ButtonTextColor.SelectedText;
            restartTrack.Clickable = true;

            noPenalty.Text = "No Penalty";
            noPenalty.Left = 80;
            noPenalty.Top = 40;
            noPenalty.Width = 20;
            noPenalty.Height = 10;
            noPenalty.TextAlignment = ButtonTextAlignment.Center;
            noPenalty.Color = ButtonColor.Dark;
            noPenalty.TextColor = ButtonTextColor.SelectedText;
            noPenalty.Clickable = true;

            dtPenalty.Text = "Drive Through";
            dtPenalty.Left = 100;
            dtPenalty.Top = 40;
            dtPenalty.Width = 20;
            dtPenalty.Height = 10;
            dtPenalty.TextAlignment = ButtonTextAlignment.Center;
            dtPenalty.Color = ButtonColor.Dark;
            dtPenalty.TextColor = ButtonTextColor.LightGrey;
            dtPenalty.Clickable = true;

            sgPenalty.Text = "Stop & Go";
            sgPenalty.Left = 120;
            sgPenalty.Top = 40;
            sgPenalty.Width = 20;
            sgPenalty.Height = 10;
            sgPenalty.TextAlignment = ButtonTextAlignment.Center;
            sgPenalty.Color = ButtonColor.Dark;
            sgPenalty.TextColor = ButtonTextColor.LightGrey;
            sgPenalty.Clickable = true;

            thirtyPenalty.Text = "30 sec";
            thirtyPenalty.Left = 80;
            thirtyPenalty.Top = 50;
            thirtyPenalty.Width = 20;
            thirtyPenalty.Height = 10;
            thirtyPenalty.TextAlignment = ButtonTextAlignment.Center;
            thirtyPenalty.Color = ButtonColor.Dark;
            thirtyPenalty.TextColor = ButtonTextColor.LightGrey;
            thirtyPenalty.Clickable = true;

            fortyfivePenalty.Text = "45 s";
            fortyfivePenalty.Left = 100;
            fortyfivePenalty.Top = 50;
            fortyfivePenalty.Width = 20;
            fortyfivePenalty.Height = 10;
            fortyfivePenalty.TextAlignment = ButtonTextAlignment.Center;
            fortyfivePenalty.Color = ButtonColor.Dark;
            fortyfivePenalty.TextColor = ButtonTextColor.LightGrey;
            fortyfivePenalty.Clickable = true;

            closeMenu.Text = "Close";
            closeMenu.Left = 50;
            closeMenu.Top = 60;
            closeMenu.Width = 30;
            closeMenu.Height = 10;
            closeMenu.TextAlignment = ButtonTextAlignment.Center;
            closeMenu.Color = ButtonColor.Dark;
            closeMenu.TextColor = ButtonTextColor.LightGrey;
            closeMenu.Clickable = true;

            header.Text = "Race Director System";
            header.Left = 50;
            header.Top = 10;
            header.Width = 100;
            header.Height = 10;
            header.TextAlignment = ButtonTextAlignment.Center;
            header.Color = ButtonColor.Dark;
            header.TextColor = ButtonTextColor.TitleColor;

            trackHeader.Text = "Track Condition:";
            trackHeader.Left = 50;
            trackHeader.Top = 20;
            trackHeader.Width = 30;
            trackHeader.Height = 10;
            trackHeader.TextAlignment = ButtonTextAlignment.Center;
            trackHeader.Color = ButtonColor.Dark;
            trackHeader.TextColor = ButtonTextColor.TitleColor;

            pitHeader.Text = "Pit Lane Condition:";
            pitHeader.Left = 50;
            pitHeader.Top = 30;
            pitHeader.Width = 30;
            pitHeader.Height = 10;
            pitHeader.TextAlignment = ButtonTextAlignment.Center;
            pitHeader.Color = ButtonColor.Dark;
            pitHeader.TextColor = ButtonTextColor.TitleColor;

            penaltyHeader.Text = "Pit Closed Penalty:";
            penaltyHeader.Left = 50;
            penaltyHeader.Top = 45;
            penaltyHeader.Width = 30;
            penaltyHeader.Height = 10;
            penaltyHeader.TextAlignment = ButtonTextAlignment.Center;
            penaltyHeader.Color = ButtonColor.Dark;
            penaltyHeader.TextColor = ButtonTextColor.TitleColor;

            handler.Configuration.LFSHost = ip;
            handler.Configuration.LFSHostPort = port;
            handler.Configuration.AdminPass = adminPass;
            handler.Configuration.UseTCP = useTCP;
            handler.Configuration.ProgramName = "Race Control System";
            handler.Configuration.UseSplitMessages = true;
            handler.Configuration.Prefix = prefix;
            handler.Configuration.MultiCarTracking = false;
            handler.Configuration.TrackingInterval = 1000;
            handler.Configuration.ReconnectRetry = 10;
            handler.Configuration.AutoReconnect = true;

            // A racer joins the server
            handler.RaceTrackConnection += new FullMotion.LiveForSpeed.InSim.EventHandlers.RaceTrackNewConnectionHandler(handler_RaceTrackConnection);

            // A racer leaves the server
            handler.RaceTrackConnectionLeave += new FullMotion.LiveForSpeed.InSim.EventHandlers.RaceTrackConnectionLeaveHandler(handler_RaceTrackConnectionLeave);

            // A message recieved from a player
            handler.LFSMessage += new FullMotion.LiveForSpeed.InSim.EventHandlers.MessageEventHandler(handler_LFSMessage);

            // A racer renames himself
            handler.RaceTrackPlayerRename += new FullMotion.LiveForSpeed.InSim.EventHandlers.RaceTrackPlayerRenameHandler(handler_RaceTrackPlayerRename);

            // A racer enters/exits the pitlane
            handler.RaceTrackPlayerPitlane += new FullMotion.LiveForSpeed.InSim.EventHandlers.RaceTrackPlayerPitlaneHandler(handler_RaceTrackPlayerPitlane);

            handler.RaceTrackPlayer += new FullMotion.LiveForSpeed.InSim.EventHandlers.RaceTrackPlayerHandler(handler_RaceTrackPlayer);

            handler.RaceTrackPlayerLeave += new FullMotion.LiveForSpeed.InSim.EventHandlers.RaceTrackPlayerLeaveHandler(handler_RaceTrackPlayerLeave);

            handler.ButtonClick += new FullMotion.LiveForSpeed.InSim.EventHandlers.ButtonClickHandler(handler_ButtonClick);

            handler.RaceTrackPlayerLap += new FullMotion.LiveForSpeed.InSim.EventHandlers.RaceTrackPlayerLapHandler(handler_RaceTrackPlayerLap);

            handler.LFSState += new FullMotion.LiveForSpeed.InSim.EventHandlers.StateEventHandler(handler_LFSState);
        }

        void handler_LFSState(InSimHandler sender, State e)
        {
            numPlayers = e.NumberOfPlayers;
        }

        void handler_RaceTrackPlayerLap(InSimHandler sender, RaceTrackPlayerLap e)
        {
            lfsracer racer = (lfsracer)racerDatabase[getConnectionid(e.PlayerId)];
            racer.lapnumber = e.LapsDone;
            racer.laptime = e.LapTime;
            racer.elapsedtime = e.TotalTime;
            //UpdateList();
        }

        void UpdateList()
        {
            //SortedList test = new SortedList();

            foreach (DictionaryEntry entry in racerDatabase)
            {
                lfsracer racer = (lfsracer)entry.Value;
                //test.Add(racer.lapnumber, racer.playername);
            }
        }

        void handler_RaceTrackPlayerLeave(InSimHandler sender, RaceTrackPlayerLeave e)
        {
            if ((racerDatabase.ContainsKey(getConnectionid(e.PlayerId))))
            {
                lfsracer racer = (lfsracer)racerDatabase[(getConnectionid(e.PlayerId))];
                racer.isracing = false;
            }
        }

        void handler_RaceTrackPlayer(InSimHandler sender, RaceTrackPlayer e)
        {
            if (racerDatabase.ContainsKey(e.ConnectionId))
            {
                lfsracer racer = (lfsracer)racerDatabase[e.ConnectionId];
                racer.playerid = e.PlayerId;
                racer.isracing = true;
            }
        }

        void handler_ButtonClick(InSimHandler sender, ButtonClick e)
        {
            if (e.ButtonId == 50)
            {
                for (int i = 0; i <= helplines; i++)
                {
                    handler.DeleteButton((byte)i, e.ConnectionId);
                }
                handler.DeleteButton(OK, e.ConnectionId);
            }

            if (e.ButtonId == 63) // Close menu button
            {
                for (int i = 53; i <= 68; i++)
                {
                    handler.DeleteButton((byte)i, e.ConnectionId);
                }
            }

            if (e.ButtonId == 53) // Pits open button
            {
                if ((trackCond == 'g') && (hideButton))
                {
                }
                else
                {
                    pitLane = 'o';
                    PitLane.TextColor = ButtonTextColor.Ok;
                    PitLane.Text = pitOpenButton;

                    handler.SendMessage("/rcm " + TextColor.Green + pitOpenText);
                    handler.SendMessage("/rcm_all");
                    // RCM message send to everyone
                    foreach (DictionaryEntry entry in racerDatabase)
                    {
                        lfsracer racer = (lfsracer)entry.Value;
                        handler.SendMessageToConnection(TextColor.Green + pitOpenText, racer.connectionid);
                        handler.ShowButton(PitLane, racer.connectionid);
                    }

                    Thread t = new Thread(new ThreadStart(ClearRCMMessages));
                    t.Name = "PitLane Open";
                    t.Start();
                }
            }

            if (e.ButtonId == 54) //Pits closed button
            {
                if ((trackCond == 'g') && (hideButton))
                {
                }
                else
                {
                    pitLane = 'c';
                    PitLane.TextColor = ButtonTextColor.Cancel;
                    PitLane.Text = pitClosedButton;
                    handler.SendMessage("/rcm " + TextColor.Red + pitClosedText);
                    handler.SendMessage("/rcm_all");
                    foreach (DictionaryEntry entry in racerDatabase)
                    {
                        lfsracer racer = (lfsracer)entry.Value;
                        handler.SendMessageToConnection(TextColor.Red + pitClosedText, racer.connectionid);
                        handler.ShowButton(PitLane, racer.connectionid);
                    }

                    Thread t = new Thread(new ThreadStart(ClearRCMMessages));
                    t.Name = "PitLane Closed";
                    t.Start();
                }
            }

            if (e.ButtonId == 55) // Green flag button
            {
                trackCond = 'g';
                TrackCond.TextColor = ButtonTextColor.Ok;
                TrackCond.Text = trackGreenButton;
                handler.SendMessage("/rcm " + TextColor.Green + greenTrackText);
                handler.SendMessage("/rcm_all");
                if (hideButton)
                {
                    foreach (DictionaryEntry entry in racerDatabase)
                    {
                        lfsracer racer = (lfsracer)entry.Value;
                        handler.SendMessageToConnection(TextColor.Green + greenTrackText, racer.connectionid);
                        handler.DeleteButton(TrackCond, racer.connectionid);
                        handler.DeleteButton(PitLane, racer.connectionid);
                    }
                }
                else
                {
                    foreach (DictionaryEntry entry in racerDatabase)
                    {
                        lfsracer racer = (lfsracer)entry.Value;
                        handler.SendMessageToConnection(TextColor.Green + greenTrackText, racer.connectionid);
                        handler.ShowButton(TrackCond, racer.connectionid);
                        handler.ShowButton(PitLane, racer.connectionid);
                    }
                }

                Thread t = new Thread(new ThreadStart(ClearRCMMessages));
                t.Name = "green flag";
                t.Start();
            }

            if (e.ButtonId == 56) // Yellow flag button
            {
                trackCond = 'y';
                TrackCond.TextColor = ButtonTextColor.TitleColor;
                TrackCond.Text = trackYellowButton;
                handler.SendMessage("/rcm " + TextColor.Yellow + yellowTrackText);
                handler.SendMessage("/rcm_all");
                foreach (DictionaryEntry entry in racerDatabase)
                {
                    lfsracer racer = (lfsracer)entry.Value;
                    handler.SendMessageToConnection(TextColor.Yellow + yellowTrackText, racer.connectionid);
                    handler.ShowButton(TrackCond, racer.connectionid);
                    handler.ShowButton(PitLane, racer.connectionid);
                }
                Thread t = new Thread(new ThreadStart(ClearRCMMessages));
                t.Name = "yellow flag";
                t.Start();
            }

            if (e.ButtonId == 57) // Red flag button
            {
                trackCond = 'r';
                TrackCond.TextColor = ButtonTextColor.Cancel;
                TrackCond.Text = trackRedButton;
                handler.SendMessage("/rcm " + TextColor.Red + redTrackText);
                handler.SendMessage("/rcm_all");
                foreach (DictionaryEntry entry in racerDatabase)
                {
                    lfsracer racer = (lfsracer)entry.Value;
                    handler.SendMessageToConnection(TextColor.Red + redTrackText, racer.connectionid);
                    handler.ShowButton(TrackCond, racer.connectionid);
                    handler.ShowButton(PitLane, racer.connectionid);
                }

                Thread t = new Thread(new ThreadStart(ClearRCMMessages));
                t.Name = "red flag";
                t.Start();
            }

            if (e.ButtonId == 68) //Restart Flag button
            {
                trackCond = 's';
                TrackCond.TextColor = ButtonTextColor.SelectedText;
                TrackCond.Text = trackRestartButton;
                handler.SendMessage("/rcm " + TextColor.White + restartTrackText);
                handler.SendMessage("/rcm_all");
                foreach (DictionaryEntry entry in racerDatabase)
                {
                    lfsracer racer = (lfsracer)entry.Value;
                    handler.SendMessageToConnection(TextColor.White + restartTrackText, racer.connectionid);
                    handler.ShowButton(TrackCond, racer.connectionid);
                    handler.ShowButton(PitLane, racer.connectionid);
                }

                Thread t = new Thread(new ThreadStart(ClearRCMMessages));
                t.Name = "Restart";
                t.Start();
            }

            if (e.ButtonId == 58) // No penalty
            {
                penalty = 0;
                noPenalty.TextColor = ButtonTextColor.SelectedText;
                dtPenalty.TextColor = ButtonTextColor.LightGrey;
                sgPenalty.TextColor = ButtonTextColor.LightGrey;
                thirtyPenalty.TextColor = ButtonTextColor.LightGrey;
                fortyfivePenalty.TextColor = ButtonTextColor.LightGrey;
                handler.ShowButton(noPenalty, e.ConnectionId);
                handler.ShowButton(dtPenalty, e.ConnectionId);
                handler.ShowButton(sgPenalty, e.ConnectionId);
                handler.ShowButton(thirtyPenalty, e.ConnectionId);
                handler.ShowButton(fortyfivePenalty, e.ConnectionId);
            }

            if (e.ButtonId == 59) // Drive-through
            {
                penalty = 1;
                noPenalty.TextColor = ButtonTextColor.LightGrey;
                dtPenalty.TextColor = ButtonTextColor.SelectedText;
                sgPenalty.TextColor = ButtonTextColor.LightGrey;
                thirtyPenalty.TextColor = ButtonTextColor.LightGrey;
                fortyfivePenalty.TextColor = ButtonTextColor.LightGrey;
                handler.ShowButton(noPenalty, e.ConnectionId);
                handler.ShowButton(dtPenalty, e.ConnectionId);
                handler.ShowButton(sgPenalty, e.ConnectionId);
                handler.ShowButton(thirtyPenalty, e.ConnectionId);
                handler.ShowButton(fortyfivePenalty, e.ConnectionId);
            }

            if (e.ButtonId == 60) // Stop-go
            {
                penalty = 2;
                noPenalty.TextColor = ButtonTextColor.LightGrey;
                dtPenalty.TextColor = ButtonTextColor.LightGrey;
                sgPenalty.TextColor = ButtonTextColor.SelectedText;
                thirtyPenalty.TextColor = ButtonTextColor.LightGrey;
                fortyfivePenalty.TextColor = ButtonTextColor.LightGrey;
                handler.ShowButton(noPenalty, e.ConnectionId);
                handler.ShowButton(dtPenalty, e.ConnectionId);
                handler.ShowButton(sgPenalty, e.ConnectionId);
                handler.ShowButton(thirtyPenalty, e.ConnectionId);
                handler.ShowButton(fortyfivePenalty, e.ConnectionId);
            }

            if (e.ButtonId == 61) // 30s
            {
                penalty = 30;
                noPenalty.TextColor = ButtonTextColor.LightGrey;
                dtPenalty.TextColor = ButtonTextColor.LightGrey;
                sgPenalty.TextColor = ButtonTextColor.LightGrey;
                thirtyPenalty.TextColor = ButtonTextColor.SelectedText;
                fortyfivePenalty.TextColor = ButtonTextColor.LightGrey;
                handler.ShowButton(noPenalty, e.ConnectionId);
                handler.ShowButton(dtPenalty, e.ConnectionId);
                handler.ShowButton(sgPenalty, e.ConnectionId);
                handler.ShowButton(thirtyPenalty, e.ConnectionId);
                handler.ShowButton(fortyfivePenalty, e.ConnectionId);
            }

            if (e.ButtonId == 62) // 45s
            {
                penalty = 45;
                noPenalty.TextColor = ButtonTextColor.LightGrey;
                dtPenalty.TextColor = ButtonTextColor.LightGrey;
                sgPenalty.TextColor = ButtonTextColor.LightGrey;
                thirtyPenalty.TextColor = ButtonTextColor.LightGrey;
                fortyfivePenalty.TextColor = ButtonTextColor.SelectedText;
                handler.ShowButton(noPenalty, e.ConnectionId);
                handler.ShowButton(dtPenalty, e.ConnectionId);
                handler.ShowButton(sgPenalty, e.ConnectionId);
                handler.ShowButton(thirtyPenalty, e.ConnectionId);
                handler.ShowButton(fortyfivePenalty, e.ConnectionId);
            }
        }

        void handler_RaceTrackPlayerPitlane(InSimHandler sender, RaceTrackPlayerPitlane e)
        {
            if ((racerDatabase.ContainsKey(getConnectionid(e.PlayerId))))
            {
                lfsracer racer = (lfsracer)racerDatabase[(getConnectionid(e.PlayerId))];
                if ((e.EventType == Pitlane.Enter) && (pitLane == 'o'))
                {
                    racer.isracing = false;
                }
                else if ((e.EventType == Pitlane.Exit) && (pitLane == 'o'))
                {
                    racer.isracing = true;
                }
                else if ((e.EventType == Pitlane.Exit) && (pitLane == 'c') && (racer.isracing == false))
                {
                    racer.isracing = true;
                }
                else if ((e.EventType == Pitlane.Exit) && (pitLane == 'c') && (racer.isracing == true))
                {
                    if (penalty == 0)
                    {
                    }
                    if (penalty == 1)
                    {
                        handler.SendMessage("/p_dt " + racer.username);
                        handler.SendMessageToConnection(TextColor.Yellow + penaltyMessage, racer.connectionid);
                    }
                    if (penalty == 2)
                    {
                        handler.SendMessage("/p_sg " + racer.username);
                        handler.SendMessageToConnection(TextColor.Yellow + penaltyMessage, racer.connectionid);
                    }
                    if (penalty == 30)
                    {
                        handler.SendMessage("/p_30 " + racer.username);
                        handler.SendMessageToConnection(TextColor.Yellow + penaltyMessage, racer.connectionid);
                    }
                    if (penalty == 45)
                    {
                        handler.SendMessage("/p_45 " + racer.username);
                        handler.SendMessageToConnection(TextColor.Yellow + penaltyMessage, racer.connectionid);
                    }
                }
            }
        }

        void handler_RaceTrackPlayerRename(InSimHandler sender, RaceTrackPlayerRename e)
        {
            if (racerDatabase.ContainsKey(e.ConnectionId))
            {
                lfsracer racer = (lfsracer)racerDatabase[e.ConnectionId];
                racer.playername = e.PlayerName;
            }
        }

        void handler_LFSMessage(InSimHandler sender, Message e)
        {
            if (racerDatabase.ContainsKey(e.ConnectionId))
            {
                lfsracer racer = (lfsracer)racerDatabase[e.ConnectionId];
                if (e.UserType == UserType.Prefix)
                {
                    if (e.MessageText.ToLower().Contains("sc"))
                    {
                        handler.SendMessageToConnection("Alert sent to the admins", racer.connectionid);
                        foreach (DictionaryEntry entry in racerDatabase)
                        {
                            lfsracer admin = (lfsracer)entry.Value;
                            if (admin.isadmin == true)
                            {
                                handler.SendMessageToConnection(racer.playername + " is alerting the admins", admin.connectionid);
                            }
                        }
                    }

                    if (e.MessageText.ToLower().Contains("help"))
                    {
                        handler.ShowButton(OK, e.ConnectionId);

                        for (int i = 0; i < this.helplines; i++)
                        {
                            handler.ShowButton(help[i], e.ConnectionId);
                        }
                    }

                    if ((e.MessageText.ToLower().Contains(adminCommand)) && (racer.isadmin))
                    {
                        handler.ShowButton(closeMenu, e.ConnectionId);
                        handler.ShowButton(openPit, e.ConnectionId);
                        handler.ShowButton(closedPit, e.ConnectionId);
                        handler.ShowButton(greenTrack, e.ConnectionId);
                        handler.ShowButton(yellowTrack, e.ConnectionId);
                        handler.ShowButton(redTrack, e.ConnectionId);
                        handler.ShowButton(restartTrack, e.ConnectionId);
                        handler.ShowButton(noPenalty, e.ConnectionId);
                        handler.ShowButton(dtPenalty, e.ConnectionId);
                        handler.ShowButton(sgPenalty, e.ConnectionId);
                        handler.ShowButton(thirtyPenalty, e.ConnectionId);
                        handler.ShowButton(fortyfivePenalty, e.ConnectionId);
                        handler.ShowButton(trackHeader, e.ConnectionId);
                        handler.ShowButton(header, e.ConnectionId);
                        handler.ShowButton(pitHeader, e.ConnectionId);
                        handler.ShowButton(penaltyHeader, e.ConnectionId);
                    }
                }
            }
        }

        void handler_RaceTrackConnection(InSimHandler sender, RaceTrackConnection e)
        {
            if (e.ConnectionId == 0)
            {

            }
            else
            {
                if (!racerDatabase.ContainsKey(e.ConnectionId))
                {
                    lfsracer racer = new lfsracer(e.UserName, e.ConnectionId);
                    racer.playername = e.PlayerName;
                    racer.isadmin = e.IsAdmin;
                    racer.isremote = e.IsRemote;
                    racerDatabase.Add(e.ConnectionId, racer);
                    if ((trackCond == 'g') && (hideButton))
                    {
                    }
                    else
                    {
                        handler.ShowButton(PitLane, e.ConnectionId);
                        handler.ShowButton(TrackCond, e.ConnectionId);
                    }
                }
            }
        }
        
        void handler_RaceTrackConnectionLeave(InSimHandler sender, RaceTrackConnectionLeave e)
        {
            if (racerDatabase.ContainsKey(e.ConnectionId))
            {
                racerDatabase.Remove(e.ConnectionId);
            }
        }

        public byte getConnectionid(byte playerid)
        {
            try
            {
                foreach (DictionaryEntry entry in racerDatabase)
                {
                    lfsracer racer = (lfsracer)entry.Value;
                    if (racer.playerid == playerid)
                        return racer.connectionid;
                }
                return (byte)0;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return (byte)0;
            }
        }

        public void Start()
        {
            try
            {
                Assembly SampleAssembly = Assembly.Load(Assembly.GetExecutingAssembly().FullName);
                foreach (Attribute a in SampleAssembly.GetCustomAttributes(true))
                {
                    if (a is AssemblyTitleAttribute)
                    {
                        fgTitle = (a as AssemblyTitleAttribute).Title;
                    }
                    if (a is AssemblyFileVersionAttribute)
                    {
                        fgVersion = (a as AssemblyFileVersionAttribute).Version;
                    }
                    if (a is AssemblyCompanyAttribute)
                    {
                        fgCompany = (a as AssemblyCompanyAttribute).Company;
                    }
                }
                Console.Title = fgTitle + " " + fgVersion;
                Console.WriteLine(fgTitle);
                Console.WriteLine("Version: " + fgVersion);
                Console.WriteLine(fgCompany);
                Console.WriteLine("Connecting");
                handler.Initialize(10);
                Console.WriteLine("Connected");
                handler.SendMessage("Race Control System Restarting...");
                handler.SendMessage(fgTitle);
                handler.SendMessage("Version: " + fgVersion);
                handler.SendMessage(fgCompany);
                handler.RequestConnectionInfo();
                handler.RequestPlayerInfo();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.Data);
                Console.ReadLine();
                Environment.Exit(0);
            }
        }

        public void Threading()
        {
            while (handler.State == InSimHandler.HandlerState.Connected)
            {
                Thread.Sleep(1); // Keep CPU usage low
            }
        }

        public void ClearRCMMessages()
        {
            int displaytime = rcmClear;

            while (displaytime > 1)
            {
                Thread.Sleep(1000);
                displaytime--;
            }

            handler.SendMessage("/rcc_all");
        }
    }
}
